﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using InductBase;
using SharpBolt.BasicIntefaces;
using SharpBolt.Graphics;
using SharpBolt.Basics;
using PowerOne.GraphicUtilites;
using OpenTK.Graphics.OpenGL;
using OpenTK.Graphics;
using OpenTK;
using InductBase.Extensions;
using SharpBolt.Graphics;
using SharpBolt;

namespace PowerOne
{
    public class OpenGLRender : IGraphicRender
    {
        public GameWindow GameWindow;

        Dictionary<string, OpenGLBitmap> OglBitmaps;

        uint uk = 0;
        public uint GetUK() { return uk++; }

        public Vec2i ScreenSize { get; set; }
        public Rec View { get; set; }

        public System.Drawing.Rectangle ClientRectangle;
        BitmapAtlas BitmapAtlas;


        public OpenGLRender()
        {
            InkColor = Colors.White;
            OglBitmaps = new Dictionary<string, OpenGLBitmap>();
            BitmapAtlas = new BitmapAtlas();
            CurrentFilter = TextureMinFilter.Linear;
        }

        public SharpBolt.Basics.SbBitmap GetBitmap(string name)
        {

            if (OglBitmaps.ContainsKey(name))
                return OglBitmaps[name];


            System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(Engine.ResourcesPrefix + name);

            Rec area;

            try
            {
                area = BitmapAtlas.AddBitmap(bmp);
            }
            catch
            {
                BitmapAtlas = new BitmapAtlas();
                area = BitmapAtlas.AddBitmap(bmp);
            }

            OpenGLBitmap result = new OpenGLBitmap(
                bmp.Size.ToVec2i(),
                GetUK(),
                name,
                BitmapAtlas,
                area
                );

            OglBitmaps.Add(name, result);
            return result;
        }

        public void FreeBitmap(string name)
        {
            if (!OglBitmaps.ContainsKey(name)) return;

            OglBitmaps.Remove(name);
        }

        public void BeginDraw()
        {

            PrepareMatrix();


        }

        private void PrepareMatrix()
        {
            ClientRectangle = this.GameWindow.ClientRectangle;

            GL.ClearColor(Color4.Black);
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

            var Projection = Matrix4.CreateOrthographic(-ClientRectangle.Width, -ClientRectangle.Height, -1, 1);
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadMatrix(ref Projection);
            GL.Translate(ClientRectangle.Width * 0.5, -ClientRectangle.Height * 0.5, 0);

            var Modelview = Matrix4.LookAt(Vector3.Zero, Vector3.UnitZ, Vector3.UnitY);
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadMatrix(ref Modelview);
        }

        public void EndDraw()
        {

        }

        BitmapAtlas lastAtlas = null;

        public void Draw(SharpBolt.Basics.SbBitmap bitmap, Vec2 position, Vec2 scale, Vec2 shift, double rotation, Color color, Rec blit)
        {
            GL.PushMatrix();
            Vec2 viewScale = ScreenSize / View.Size;
            GL.Scale(viewScale.X, viewScale.Y, 1);
            GL.Translate(-View.Location.X, -View.Location.Y, 0);

            GL.PushMatrix();
            GL.Translate(position.X, position.Y, 0);
            GL.Rotate(rotation, 0, 0, 1);
            GL.Scale(scale.X, scale.Y, 1);
            GL.Translate(shift.X, shift.Y, 0);

            OpenGLBitmap obitmap = bitmap as OpenGLBitmap;

            if (obitmap.Atlas!= null && !obitmap.Atlas.IsBaked)
            {
                obitmap.Atlas.BakeAtlas();
            }

            if (obitmap.Atlas != lastAtlas)
            {
                obitmap.Atlas.Texture.Bind();
                lastAtlas = obitmap.Atlas;

#if DEBUG
                obitmap.Atlas.Bitmap.Save("atlas.png");
#endif
            }

            

            DColor ink = InkColor.ToDColor();

            double toFlt = 1.0f / 255f;
            GL.Color4(new Color4(
                (float)(color.R * toFlt * ink.r),
                (float)(color.G * toFlt * ink.g),
                (float)(color.B * toFlt * ink.b),
                (float)(color.A * toFlt * ink.a)
                ));

            GL.Begin(BeginMode.Quads);
            Rec coords = new Rec(0, 0, 1, 1);

            coords.Location = (obitmap.AtlasArea.Location + blit.Location) / obitmap.Atlas.Size;
            coords.Size = blit.Size / obitmap.Atlas.Size;

            Rec quad = Rec.FromLocationSize(Vec2.Null, blit.Size);

            GL.TexCoord2(coords.Min.X, coords.Max.Y);
            GL.Vertex2(quad.Min.X, quad.Max.Y);

            GL.TexCoord2(coords.Min.X, coords.Min.Y);
            GL.Vertex2(quad.Min.X, quad.Min.Y);

            GL.TexCoord2(coords.Max.X, coords.Min.Y);
            GL.Vertex2(quad.Max.X, quad.Min.Y);

            GL.TexCoord2(coords.Max.X, coords.Max.Y);
            GL.Vertex2(quad.Max.X, quad.Max.Y);


            GL.End();
            GL.PopMatrix();
            GL.PopMatrix();
        }

        static public TextureMinFilter CurrentFilter { get; private set; }

        static public void SetFiltering(TextureMinFilter filter)
        {
            CurrentFilter = filter;
        }


        public Color InkColor { set; get; }

    }
}
